
//Para leer imagenes dicom
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkImageSeriesWriter.h"

// some standard vtk headers
#include <vtkSmartPointer.h>
#include <vtkObjectFactory.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkActor.h>
#include <vtkImageViewer2.h>
#include <vtkDICOMImageReader.h>
#include <vtkInteractorStyleImage.h>
#include <vtkActor2D.h>
#include <vtkTextProperty.h>
#include <vtkTextMapper.h>
// estandar de x++
#include <sstream>
#include <iostream>
#include <vector>
#include <stdlib.h>

//Varios
#include "itksys/SystemTools.hxx"

//Binarizacion por nivel
#include "itkBinaryThresholdImageFilter.h"

//Operaciones morfologicas
#include "itkBinaryBallStructuringElement.h"
#include "itkFlatStructuringElement.h"
#include "itkSubtractImageFilter.h"
#include "itkBinaryMorphologicalClosingImageFilter.h"
#include "itkBinaryMorphologicalOpeningImageFilter.h"
#include "itkBinaryNotImageFilter.h"
//Filtro itk vtk
#include <itkImageToVTKImageFilter.h>

//Diccionario metadata
#include "itkMetaDataObject.h"

//Etiquetado de regiones
#include "itkBinaryImageToShapeLabelMapFilter.h"
#include "itkImage.h"

//Quick view
#include "itkImageFileReader.h"
#include "itkRescaleIntensityImageFilter.h"
#include "QuickView.h"

//Conocer valor de pixel
#include <vtkPointPicker.h>
#include <vtkRendererCollection.h>

//Crecimiento de regiones
#include "itkConnectedThresholdImageFilter.h"
#include "itkCastImageFilter.h"
#include "itkCurvatureFlowImageFilter.h"
//Filtro or
#include "itkOrImageFilter.h"

//Filtro cast
#include "itkCastImageFilter.h"

//Duplicar imagen
#include "itkImageDuplicator.h"

//Label
#include "itkLabelMapToLabelImageFilter.h"
#include "itkLabelStatisticsImageFilter.h"

//Histograma
#include "itkImageToHistogramFilter.h"
#include "itkImageRegionIteratorWithIndex.h"



//Algunas typedef
	typedef signed short    PixelType;
	typedef unsigned char   PixelBinaryType;
	const unsigned int      Dimension = 3;
	
	typedef itk::Image< PixelType, Dimension > ImageType;
	typedef itk::Image<PixelBinaryType, Dimension> ImageBinaryType;
	typedef itk::ImageSeriesReader< ImageType > ReaderType;
	
	/*Como en el ejemplo
	typedef signed short    OutputPixelType;
	const unsigned int      OutputDimension = 2;
	typedef itk::Image< OutputPixelType, OutputDimension >    Image2DType;
	typedef itk::ImageSeriesWriter<ImageType, Image2DType >  SeriesWriterType;
	*/
	//typedef unsigned char    OutputPixelType;
	typedef unsigned char   OutputPixelType;
	const unsigned int      OutputDimension = 2;
	typedef itk::Image< OutputPixelType, OutputDimension >    Image2DType;
	typedef itk::ImageSeriesWriter<ImageBinaryType, Image2DType >  SeriesWriterType;
	
	ImageType::Pointer imageIn;
	ImageBinaryType::Pointer imageOut;
	ImageBinaryType::Pointer mediastino;
	ImageBinaryType::Pointer pulmones;
	ImageBinaryType::Pointer vasosGrandes;


using namespace std;

// helper class to format slice status message
class StatusMessage {
public:
   static std::string Format(int slice, int maxSlice) {
      std::stringstream tmp;
      tmp << "Slice Number  " << slice + 1 << "/" << maxSlice + 1;
      return tmp.str();
   }
};
 
// Define own interaction style
class myVtkInteractorStyleImage : public vtkInteractorStyleImage
{
public:
   static myVtkInteractorStyleImage* New();
   vtkTypeMacro(myVtkInteractorStyleImage, vtkInteractorStyleImage);
 
protected:
   vtkImageViewer2* _ImageViewer;
   vtkTextMapper* _StatusMapper;
   int _Slice;
   int _MinSlice;
   int _MaxSlice;
 
public:
   void SetImageViewer(vtkImageViewer2* imageViewer) {
      _ImageViewer = imageViewer;
      _MinSlice = imageViewer->GetSliceMin();
      _MaxSlice = imageViewer->GetSliceMax();
      _Slice = _MinSlice;
      //cout << "Slicer: Min = " << _MinSlice << ", Max = " << _MaxSlice << std::endl;
   }
 
   void SetStatusMapper(vtkTextMapper* statusMapper) {
      _StatusMapper = statusMapper;
   }
 
 
protected:
   void MoveSliceForward() {
      if(_Slice < _MaxSlice) {
         _Slice += 1;
         //cout << "MoveSliceForward::Slice = " << _Slice << std::endl;
         _ImageViewer->SetSlice(_Slice);
         std::string msg = StatusMessage::Format(_Slice, _MaxSlice);
         _StatusMapper->SetInput(msg.c_str());
         _ImageViewer->Render();
      }
   }
 
   void MoveSliceBackward() {
      if(_Slice > _MinSlice) {
         _Slice -= 1;
         //cout << "MoveSliceBackward::Slice = " << _Slice << std::endl;
         _ImageViewer->SetSlice(_Slice);
         std::string msg = StatusMessage::Format(_Slice, _MaxSlice);
         _StatusMapper->SetInput(msg.c_str());
         _ImageViewer->Render();
      }
   }
 
 
   virtual void OnKeyDown() {
      std::string key = this->GetInteractor()->GetKeySym();
      if(key.compare("Up") == 0) {
         //cout << "Up arrow key was pressed." << endl;
         MoveSliceForward();
      }
      else if(key.compare("Down") == 0) {
         //cout << "Down arrow key was pressed." << endl;
         MoveSliceBackward();
      }
      // forward event
      vtkInteractorStyleImage::OnKeyDown();
   }
 
 
   virtual void OnMouseWheelForward() {
      //std::cout << "Scrolled mouse wheel forward." << std::endl;
      MoveSliceForward();
      // don't forward events, otherwise the image will be zoomed 
      // in case another interactorstyle is used (e.g. trackballstyle, ...)
      // vtkInteractorStyleImage::OnMouseWheelForward();
   }
 
 
   virtual void OnMouseWheelBackward() {
      //std::cout << "Scrolled mouse wheel backward." << std::endl;
      if(_Slice > _MinSlice) {
         MoveSliceBackward();
      }
      // don't forward events, otherwise the image will be zoomed 
      // in case another interactorstyle is used (e.g. trackballstyle, ...)
      // vtkInteractorStyleImage::OnMouseWheelBackward();
   }
   
	virtual void OnLeftButtonDown() 
    {
      std::cout << "Picking pixel: " << this->Interactor->GetEventPosition()[0] << " " << this->Interactor->GetEventPosition()[1] << std::endl;
      this->Interactor->GetPicker()->Pick(this->Interactor->GetEventPosition()[0], 
                         this->Interactor->GetEventPosition()[1], 
                         0,  // always zero.
                         this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer());
      double picked[3];
      this->Interactor->GetPicker()->GetPickPosition(picked);
      std::cout << "Picked value: " << picked[0] << " " << picked[1] << " " << picked[2] << std::endl;
      // Forward events
      //vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
	  
	  ImageType::IndexType currentIndex;
	  currentIndex[0] = picked[0];
	  currentIndex[1] = picked[1];
	  currentIndex[2] = picked[2];
	  
	  ImageBinaryType::IndexType currentIndex2;
	  currentIndex2[0] = picked[0];
	  currentIndex2[1] = picked[1];
	  currentIndex2[2] = picked[2];
	  
	  
	  
	  ImageType::PixelType currentValueIn = imageIn->GetPixel(currentIndex);
	  //ImageBinaryType::PixelType currentValueOut = imageOut->GetPixel(currentIndex);
	  
	  cout<<"valor en imagen de entrada: "<<currentValueIn<<endl;
	  //cout<<"valor en imagen de salida: "<<(currentValueOut)<<endl;
	  
    }
};
 
vtkStandardNewMacro(myVtkInteractorStyleImage);


//Interaccion con mouse Trackball para saber la ubicacion de un pixel, aunque ya se copio yu pego en el estilo de arriba.
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Define interaction style
class MouseInteractorStylePP : public vtkInteractorStyleTrackballCamera
{
  public:
    static MouseInteractorStylePP* New();
    vtkTypeMacro(MouseInteractorStylePP, myVtkInteractorStyleImage);
 
    virtual void OnLeftButtonDown() 
    {
      std::cout << "Picking pixel: " << this->Interactor->GetEventPosition()[0] << " " << this->Interactor->GetEventPosition()[1] << std::endl;
      this->Interactor->GetPicker()->Pick(this->Interactor->GetEventPosition()[0], 
                         this->Interactor->GetEventPosition()[1], 
                         0,  // always zero.
                         this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer());
      double picked[3];
      this->Interactor->GetPicker()->GetPickPosition(picked);
      std::cout << "Picked value: " << picked[0] << " " << picked[1] << " " << picked[2] << std::endl;
      // Forward events
      vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
    }
 
};

vtkStandardNewMacro(MouseInteractorStylePP);

///////////////////////////////////////////////////////////////////////////////////////////////////////////




//Funciones
void UmbralizacionNivel(signed short lower, signed short upper);
void leerImagenes(string folder,string folder2);
void leerEncabezado (string nombre);
double obtenerValorDePixel(string nombreDir);
double obtenerValorDePixel(itk::GDCMImageIO::Pointer dicomIO);
void imprimirMatriz(ImageType::Pointer image);


int main( int argc, char* argv[] )
{
	//Lectura de las imagenes DICOM
	if( argc < 3 )
    {
    std::cerr << "Usage: " << argv[0] <<
      " DicomDirectory  OutputDicomDirectory" << std::endl;
    return EXIT_FAILURE;
    }
  

	ReaderType::Pointer reader = ReaderType::New();
	typedef itk::GDCMImageIO ImageIOType;
  
	ImageIOType::Pointer gdcmIO = ImageIOType::New();
  
	reader->SetImageIO( gdcmIO );

	typedef itk::GDCMSeriesFileNames NamesGeneratorType;
	NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New();

	namesGenerator->SetInputDirectory( argv[1] );

	const ReaderType::FileNamesContainer & filenames = namesGenerator->GetInputFileNames();

	unsigned int numberOfFilenames =  filenames.size();

	reader->SetFileNames( filenames );

	try
    {
		reader->Update();
    }
	catch (itk::ExceptionObject &excp)
	{
		std::cerr << "Exception thrown while writing the image" << std::endl;
		std::cerr << excp << std::endl;
		return EXIT_FAILURE;
    }

	imageIn = reader->GetOutput();
  
  
	//Lectura del valor en mm del pixel para hacer las operaciones correspondientes
    double tamPixel = obtenerValorDePixel(gdcmIO);
	cout<<" valor del pixel  : "<<tamPixel<<endl;
  
  
	//1. Segmentacion de pulmones Binarizacion por crecimiento de regiones.
	

	typedef itk::CastImageFilter< ImageType, ImageType > CastingFilterType;	
	CastingFilterType::Pointer caster = CastingFilterType::New();
	CastingFilterType::Pointer caster2 = CastingFilterType::New();
	
	typedef itk::CurvatureFlowImageFilter< ImageType, ImageType > CurvatureFlowImageFilterType;
	CurvatureFlowImageFilterType::Pointer smoothing = CurvatureFlowImageFilterType::New();
	CurvatureFlowImageFilterType::Pointer smoothing2 = CurvatureFlowImageFilterType::New();
	
	typedef itk::ConnectedThresholdImageFilter< ImageType,ImageType > ConnectedFilterType;
	ConnectedFilterType::Pointer connectedThreshold = ConnectedFilterType::New();
	ConnectedFilterType::Pointer connectedThreshold2 = ConnectedFilterType::New();
	
	smoothing->SetInput( reader->GetOutput() );
	smoothing2->SetInput( reader->GetOutput() );
	connectedThreshold->SetInput( smoothing->GetOutput());
	connectedThreshold2->SetInput( smoothing2->GetOutput() );
	caster->SetInput( connectedThreshold->GetOutput() );
	caster2->SetInput( connectedThreshold2->GetOutput() );
	
	smoothing->SetNumberOfIterations( 5 );
	smoothing2->SetNumberOfIterations( 5 );
	//smoothing->SetTimeStep( 0.125 );
	smoothing->SetTimeStep( 0.025 );
	smoothing2->SetTimeStep( 0.025 );
	
	const PixelType lowerThreshold = -2000;
	const PixelType upperThreshold = -500;
	
	connectedThreshold->SetLower(  lowerThreshold  );
	connectedThreshold->SetUpper(  upperThreshold  );
	
	connectedThreshold2->SetLower(  lowerThreshold  );
	connectedThreshold2->SetUpper(  upperThreshold  );
	
	//connectedThreshold->SetReplaceValue( 32767 );
	connectedThreshold->SetReplaceValue( 32767 );
	connectedThreshold2->SetReplaceValue( 32767 );
	
	ImageType::IndexType semillaPulmonIzq;
	semillaPulmonIzq[0] = 302.132;
	semillaPulmonIzq[1] = 167.741;
	semillaPulmonIzq[2] = 2.49996;
	
	ImageType::IndexType semillaPulmonDer;
	semillaPulmonDer[0] = 109.684;
	semillaPulmonDer[1] = 224.723;
	semillaPulmonDer[2] = 1.24995;
	
	connectedThreshold->SetSeed( semillaPulmonIzq );
	connectedThreshold2->SetSeed( semillaPulmonDer );
	

	//Filtro de casteo de una imagen short a una char
	typedef itk::CastImageFilter< ImageType, ImageBinaryType > CastFilterType;
	CastFilterType::Pointer castFilter = CastFilterType::New();
	CastFilterType::Pointer castFilter2 = CastFilterType::New();
	castFilter->SetInput(connectedThreshold->GetOutput());
	castFilter2->SetInput(connectedThreshold2->GetOutput());

	

	//Operacion or
	typedef itk::OrImageFilter <ImageBinaryType> OrImageFilterType;
	OrImageFilterType::Pointer orFilter = OrImageFilterType::New();
	
	orFilter->SetInput(0, castFilter->GetOutput());
	orFilter->SetInput(1, castFilter2->GetOutput());
	orFilter->Update();
	
	
	//imageBinary=orFilter->GetOutput();
	pulmones=orFilter->GetOutput();

	//1.1: closing de 2.4mm
	
	double radius = (double)2.4/tamPixel;
	cout<<"radio de closing : "<<radius<<"  pixeles " <<endl;
	
	typedef itk::BinaryBallStructuringElement<ImageBinaryType::PixelType, ImageBinaryType::ImageDimension> StructuringElementType;
	StructuringElementType structuringElement;
	structuringElement.SetRadius(radius);
	structuringElement.CreateStructuringElement();
  
	typedef itk::BinaryMorphologicalClosingImageFilter <ImageBinaryType, ImageBinaryType, StructuringElementType> BinaryMorphologicalClosingImageFilterType;
	BinaryMorphologicalClosingImageFilterType::Pointer closingFilter = BinaryMorphologicalClosingImageFilterType::New();
	closingFilter->SetInput(pulmones);
	closingFilter->SetKernel(structuringElement);
	closingFilter->Update();
	
	cout<<"se hizo el closing"<<endl;

	pulmones=closingFilter->GetOutput();
	//imageBinary=closingFilter->GetOutput();

	//2. Mediastino
	
	//2.1: operacion row-wise
	
	//Copia de la anterior imagen, la salida del filtro del closing
	typedef itk::ImageDuplicator< ImageBinaryType > DuplicatorType;
	DuplicatorType::Pointer duplicator = DuplicatorType::New();
	duplicator->SetInputImage(pulmones);
	duplicator->Update();
	ImageBinaryType::Pointer copyOfClosingFilter = duplicator->GetOutput();
	 
	//Deja toda la matriz en 0
	//ImageBinaryType::Pointer copia = copyOfClosingFilter->GetOutput();
	ImageBinaryType::SizeType size = copyOfClosingFilter->GetLargestPossibleRegion().GetSize();
	ImageBinaryType::IndexType index = copyOfClosingFilter->GetLargestPossibleRegion().GetIndex();
		
	for (int i=0 ; i< size[0] ; i++)
	{
		for (int j=0; j< size[1]; j++)
		{
			for (int k=0; k<size [2]; k++)
			{
				ImageBinaryType::IndexType currentIndex;
				currentIndex[0] = i;
				currentIndex[1] = j;
				currentIndex[2] = k;
				//ImageBinaryType::PixelType currentValue = copyOfClosingFilter->GetPixel(currentIndex);
				
				copyOfClosingFilter->SetPixel(currentIndex,(char)(0));
			}	
		}
	}

	//Etiquetado de regiones de la imagen binaria, no de la copia:
	 typedef itk::BinaryImageToShapeLabelMapFilter<ImageBinaryType> BinaryImageToShapeLabelMapFilterType;
	 BinaryImageToShapeLabelMapFilterType::Pointer binaryImageToShapeLabelMapFilter = BinaryImageToShapeLabelMapFilterType::New();
	 binaryImageToShapeLabelMapFilter->SetInput(pulmones);
	 binaryImageToShapeLabelMapFilter->Update();
	 
	 // The output of this filter is an itk::ShapeLabelMap, which contains itk::ShapeLabelObject's
	//cout << "There are " << binaryImageToShapeLabelMapFilter->GetOutput()->GetNumberOfLabelObjects() << " objects." << std::endl;
 
	//De acuerdo al bounding box de la region pulmonar se pone en 1 los pixeles de la imagen copia, donde hay un 1 en la imagen binaria
	for(unsigned int i = 0; i < binaryImageToShapeLabelMapFilter->GetOutput()->GetNumberOfLabelObjects(); i++)
    {
		BinaryImageToShapeLabelMapFilterType::OutputImageType::LabelObjectType* labelObject = binaryImageToShapeLabelMapFilter->GetOutput()->GetNthLabelObject(i);
		//std::cout << "Object " << i << " has bounding box " << labelObject->GetBoundingBox() << std::endl;
		
		unsigned int ii,j,k;
		unsigned int sizex=labelObject->GetBoundingBox().GetSize()[0];
		unsigned int sizey=labelObject->GetBoundingBox().GetSize()[1];
		unsigned int sizez=labelObject->GetBoundingBox().GetSize()[2];
		unsigned errory=10;
		unsigned errorx=30;
		
			for (ii=labelObject->GetBoundingBox().GetIndex()[0]+errorx; ii< (labelObject->GetBoundingBox().GetIndex()[0])+sizex-errorx;ii++)
			{
				for (j=labelObject->GetBoundingBox().GetIndex()[1]+errory; j< (labelObject->GetBoundingBox().GetIndex()[1])+sizey-(2*errory);j++)
				{
					for (k=labelObject->GetBoundingBox().GetIndex()[2];k<labelObject->GetBoundingBox().GetIndex()[2]+sizez; k++)
					{
						
						ImageBinaryType::IndexType currentIndex;
						currentIndex[0] = ii;
						currentIndex[1] = j;
						currentIndex[2] = k;
						ImageBinaryType::PixelType currentValue = pulmones->GetPixel(currentIndex);
						
						if(int(currentValue)!=255){
							copyOfClosingFilter->SetPixel(currentIndex,char(255));
						}
						else
						{	
							copyOfClosingFilter->SetPixel(currentIndex,char(0));
						}
					}
				}
			}
    }
	
	//Etiquetado para la ultima imagen
	typedef itk::BinaryImageToLabelMapFilter<ImageBinaryType> BinaryImageToLabelMapFilterType;
	BinaryImageToLabelMapFilterType::Pointer binaryImageToLabelMapFilter = BinaryImageToLabelMapFilterType::New();
	binaryImageToLabelMapFilter->SetInput(copyOfClosingFilter);
	binaryImageToLabelMapFilter->Update();
	
	typedef itk::LabelMapToLabelImageFilter<BinaryImageToLabelMapFilterType::OutputImageType, ImageBinaryType> LabelMapToLabelImageFilterType;
	LabelMapToLabelImageFilterType::Pointer labelMapToLabelImageFilter = LabelMapToLabelImageFilterType::New();
	labelMapToLabelImageFilter->SetInput(binaryImageToLabelMapFilter->GetOutput());
	labelMapToLabelImageFilter->Update();
	
	typedef itk::LabelStatisticsImageFilter< ImageBinaryType, ImageBinaryType > LabelStatisticsImageFilterType;
	LabelStatisticsImageFilterType::Pointer labelStatisticsImageFilter = LabelStatisticsImageFilterType::New();
	labelStatisticsImageFilter->SetLabelInput( labelMapToLabelImageFilter->GetOutput() );
	labelStatisticsImageFilter->SetInput(copyOfClosingFilter);
	labelStatisticsImageFilter->Update();
 
	//std::cout << "Number of labels: " << labelStatisticsImageFilter->GetNumberOfLabels() << std::endl;
	//std::cout << std::endl;
 	
	unsigned int maximo=0;
	unsigned int ValorMax=0;
	unsigned int pos=0;
	
	typedef LabelStatisticsImageFilterType::ValidLabelValuesContainerType ValidLabelValuesType;
	typedef LabelStatisticsImageFilterType::LabelPixelType                LabelPixelType; 
	 
	 //Se calcula la region mas grande que corresponde al mediastino
	for(ValidLabelValuesType::const_iterator vIt=labelStatisticsImageFilter->GetValidLabelValues().begin();
      vIt != labelStatisticsImageFilter->GetValidLabelValues().end();
      ++vIt)
    {
		if ( labelStatisticsImageFilter->HasLabel(*vIt) )
		{
			LabelPixelType labelValue = *vIt;
						
			//std::cout << "sum: " << labelStatisticsImageFilter->GetSum( labelValue ) << std::endl;
			//std::cout << "region: " << labelStatisticsImageFilter->GetRegion( labelValue ) << std::endl;
			
			if(labelStatisticsImageFilter->GetSum( labelValue )>ValorMax){
				ValorMax=labelStatisticsImageFilter->GetSum( labelValue );
				maximo=pos;
			}

		}
		pos++;
	}
	
	//cout<<"El maxiomo es "<<maximo<<endl;
	//cout<<"El volumen es "<<ValorMax<<endl;
	pos=0;
	
	
	//Para borrar regiones pequeñas y dejar solo el mediastino
	for(ValidLabelValuesType::const_iterator vIt=labelStatisticsImageFilter->GetValidLabelValues().begin();
      vIt != labelStatisticsImageFilter->GetValidLabelValues().end();
      ++vIt)
    {
		if ( labelStatisticsImageFilter->HasLabel(*vIt) )
		{
			LabelPixelType labelValue = *vIt;
						
			if(pos!=maximo && pos!=0 ){
							//std::cout << "sum: " << labelStatisticsImageFilter->GetSum( labelValue ) << std::endl;
							//std::cout << "region: " << labelStatisticsImageFilter->GetRegion( labelValue ) << std::endl;
						unsigned int ii,j,k;
						unsigned int sizex=labelStatisticsImageFilter->GetRegion( labelValue ).GetSize()[0];
						unsigned int sizey=labelStatisticsImageFilter->GetRegion( labelValue ).GetSize()[1];
						unsigned int sizez=labelStatisticsImageFilter->GetRegion( labelValue ).GetSize()[2];
						
							for (ii=labelStatisticsImageFilter->GetRegion( labelValue ).GetIndex()[0]; ii< (labelStatisticsImageFilter->GetRegion( labelValue ).GetIndex()[0])+sizex;ii++)
							{
								for (j=labelStatisticsImageFilter->GetRegion( labelValue ).GetIndex()[1]; j< (labelStatisticsImageFilter->GetRegion( labelValue ).GetIndex()[1])+sizey;j++)
								{
									for (k=labelStatisticsImageFilter->GetRegion( labelValue ).GetIndex()[2];k<labelStatisticsImageFilter->GetRegion( labelValue ).GetIndex()[2]+sizez; k++)
									{
										
										ImageBinaryType::IndexType currentIndex;
										currentIndex[0] = ii;
										currentIndex[1] = j;
										currentIndex[2] = k;
										ImageBinaryType::PixelType currentValue = copyOfClosingFilter->GetPixel(currentIndex);
											copyOfClosingFilter->SetPixel(currentIndex,char(0));
									}
								}
							}
			}

		}
		pos++;
	}
	//mediastino=copyOfClosingFilter->GetOutput();
	
	//2.2: opening de 6 mm
	
	double radius2=(double)6/tamPixel;
	cout<<"radio de opening : "<<radius2<<"  pixeles " <<endl;
	
	//Elemento bola
	typedef itk::BinaryBallStructuringElement<ImageBinaryType::PixelType, ImageBinaryType::ImageDimension> StructuringElementType2;
	StructuringElementType2 structuringElement2;
	structuringElement2.SetRadius(radius2);
	structuringElement2.CreateStructuringElement();

	//operacion morfologica
	typedef itk::BinaryMorphologicalOpeningImageFilter< ImageBinaryType,ImageBinaryType,StructuringElementType2> BinaryMorphologicalOpeningImageFilterType;
	BinaryMorphologicalOpeningImageFilterType::Pointer openingFilter= BinaryMorphologicalOpeningImageFilterType::New();
	openingFilter->SetInput(copyOfClosingFilter);
	openingFilter->SetKernel(structuringElement2);
	openingFilter->Update();
	
	cout<<"se hizo el opening"<<endl;
	
	mediastino=openingFilter->GetOutput();
	
	
	//3. Major pulmonary vessels
	
	//Histograma de la imagen:
	/*
	const unsigned int MeasurementVectorSize = 1; // Grayscale
	const unsigned int binsPerDimension = 10;
	
	typedef itk::Statistics::ImageToHistogramFilter< ImageType > ImageToHistogramFilterType;
	ImageToHistogramFilterType::HistogramType::MeasurementVectorType lowerBound(binsPerDimension);
	lowerBound.Fill(0);
	
	ImageToHistogramFilterType::HistogramType::MeasurementVectorType upperBound(binsPerDimension);
	upperBound.Fill(10) ;
	
	 ImageToHistogramFilterType::HistogramType::SizeType size(MeasurementVectorSize);
	 size.Fill(binsPerDimension);
	
	  ImageToHistogramFilterType::Pointer imageToHistogramFilter = ImageToHistogramFilterType::New();
	  imageToHistogramFilter->SetInput(imageIn);
	  imageToHistogramFilter->SetHistogramBinMinimum(lowerBound);
	  imageToHistogramFilter->SetHistogramBinMaximum(upperBound);
	  imageToHistogramFilter->SetHistogramSize(size);
	  imageToHistogramFilter->Update();
	  
	  ImageToHistogramFilterType::HistogramType* histogram = imageToHistogramFilter->GetOutput();
		
		cout<<"cantidad de elementos: "<<histogram->GetSize()[0]<<endl;
	  std::cout << "Frequency = ";
	  for(unsigned int i = 0; i < histogram->GetSize()[0]; ++i)
		{
		std::cout << histogram->GetFrequency(i) << "  ";
		}
	 
	  std::cout << std::endl;*/
	  
	  
	  
	  
	  
	  /*
	  //Calculo de las frecuencias:
	  
	//imprimirMatriz(reader->GetOutput()); //No SIRVE 
  
 	//ImageType::Pointer image = openingFilter->GetOutput();
	ImageType::SizeType sizeIn = imageIn->GetLargestPossibleRegion().GetSize();
	ImageType::IndexType indexIn = imageIn->GetLargestPossibleRegion().GetIndex();
  
	unsigned int frec0=0;
	unsigned int frecUmbral=0;
	unsigned int frecMayor=150;
	unsigned int valorfrecmayor=0;
	
	int valorMayor=1500;
	unsigned int hist [valorMayor]; //el primer valor es de +500 HU
	
	
	//Se llena el vector de 0
	for (int i=0;i<valorMayor;i++){
		hist[i]=0;
	}
	
	
	cout<<" Size :  "<<sizeIn<<endl;
	for (int i=0 ; i< sizeIn[0] ; i++)
	{
		for (int j=0; j< sizeIn[1]; j++)
		{
			for (int k=0; k<sizeIn [2]; k++)
			{
				
				ImageType::IndexType currentIndex;
				currentIndex[0] = i;
				currentIndex[1] = j;
				currentIndex[2] = k;
				ImageType::PixelType currentValue = imageIn->GetPixel(currentIndex);
				
				if(currentValue>=150){
					hist[currentValue-valorMayor]++;
				}
				if(currentValue==0){
					frec0++;
				}
				if(currentValue==78){
					frecUmbral++;
				}
			}
		}
	}
	
	for (int i=0;i<valorMayor;i++){
		cout<<hist[i]<<", " ;
		if(hist[i]>valorfrecmayor){
			valorfrecmayor=hist[i];
			frecMayor=i+150;
		}
	}
	
	
	cout<<endl;
	cout<<"frec de cero "<<frec0<<endl;
	cout<<"frec de umbral 78 "<<frecUmbral<<"  --- "<<endl;
	cout<<"frec de "<<frecMayor<<" : "<<valorfrecmayor<<endl;
		signed short umbral=frecMayor/2;
	cout<<"umbral " <<umbral<<endl;
	
	
	typedef itk::CastImageFilter< ImageType, ImageType > CastingFilterTypeMed;	
	CastingFilterTypeMed::Pointer casterMed = CastingFilterTypeMed::New();
	
	typedef itk::CurvatureFlowImageFilter< ImageType, ImageType > CurvatureFlowImageFilterTypeMed;
	CurvatureFlowImageFilterTypeMed::Pointer smoothingMed = CurvatureFlowImageFilterTypeMed::New();

	typedef itk::ConnectedThresholdImageFilter< ImageType,ImageType > ConnectedFilterTypeMed;
	ConnectedFilterTypeMed::Pointer connectedThresholdMed = ConnectedFilterTypeMed::New();


	smoothingMed->SetInput( reader->GetOutput() );
	connectedThresholdMed->SetInput( smoothingMed->GetOutput());
	casterMed->SetInput( connectedThresholdMed->GetOutput() );

	
	smoothingMed->SetNumberOfIterations( 5 );
	//smoothing->SetTimeStep( 0.125 );
	smoothingMed->SetTimeStep( 0.025 );

	const PixelType lowerThresholdMed = -408;
	const PixelType upperThresholdMed = -200;
	
	connectedThresholdMed->SetLower(  lowerThresholdMed  );
	connectedThresholdMed->SetUpper(  upperThresholdMed  );

	//connectedThreshold->SetReplaceValue( 32767 );
	connectedThresholdMed->SetReplaceValue( 32767 );

	
	ImageType::IndexType semillaMed;
	semillaMed[0] = 213.972;
	semillaMed[1] = 195.964;
	semillaMed[2] = 3.74999;
	connectedThresholdMed->SetSeed( semillaMed );
	
	
	
		//Filtro de casteo de una imagen short a una char
	typedef itk::CastImageFilter< ImageType, ImageBinaryType > CastFilterTypeMed;
	CastFilterTypeMed::Pointer castFilterMed = CastFilterTypeMed::New();

	castFilterMed->SetInput(connectedThresholdMed->GetOutput());
	
	
	typedef itk::OrImageFilter <ImageBinaryType> OrImageFilterType2;
	OrImageFilterType2::Pointer orFilter2 = OrImageFilterType2::New();
	
	orFilter2->SetInput(0, castFilterMed->GetOutput());
	orFilter2->SetInput(1, castFilterMed->GetOutput());
	orFilter2->Update();
	
	
	vasosGrandes=orFilter2->GetOutput();


	ImageType::SizeType sizeI = imageIn->GetLargestPossibleRegion().GetSize();
	ImageType::IndexType indexI = imageIn->GetLargestPossibleRegion().GetIndex();
  

	for (int i=0 ; i< sizeI[0] ; i++)
	{
		for (int j=0; j< sizeI[1]; j++)
		{
			for (int k=0; k<sizeI [2]; k++)
			{
				
				ImageType::IndexType currentIndex;
				currentIndex[0] = i;
				currentIndex[1] = j;
				currentIndex[2] = k;
				ImageType::PixelType currentValue = imageIn->GetPixel(currentIndex);

				ImageBinaryType::IndexType currentIndexB;
				currentIndexB[0] = i;
				currentIndexB[1] = j;
				currentIndexB[2] = k;
				
				if(currentValue==umbral){
					cout<<" cuurent "<<currentIndexB<<endl;
					vasosGrandes->SetPixel(currentIndexB,char(255));
				}
			}
		}
	}
	*/
	
	//4.Segmentacion de vasos perifericos
	
	//Copia de la imagen del pulmon
	typedef itk::ImageDuplicator< ImageBinaryType > DuplicatorTypeLung;
	DuplicatorTypeLung::Pointer duplicatorLung = DuplicatorTypeLung::New();
	duplicatorLung->SetInputImage(pulmones);
	duplicatorLung->Update();
	ImageBinaryType::Pointer copyOfLungs = duplicatorLung->GetOutput();
	
	//Deja toda la matriz de copia de la imagen de pulmones en 0
	//ImageBinaryType::Pointer copia = copyOfClosingFilter->GetOutput();
	ImageBinaryType::SizeType sizeLung = copyOfLungs->GetLargestPossibleRegion().GetSize();
	ImageBinaryType::IndexType indexLung = copyOfLungs->GetLargestPossibleRegion().GetIndex();
		
	for (int i=0 ; i< sizeLung[0] ; i++)
	{
		for (int j=0; j< sizeLung[1]; j++)
		{
			for (int k=0; k<sizeLung [2]; k++)
			{
				ImageBinaryType::IndexType currentIndexLung;
				currentIndexLung[0] = i;
				currentIndexLung[1] = j;
				currentIndexLung[2] = k;
				//ImageBinaryType::PixelType currentValue = copyOfClosingFilter->GetPixel(currentIndex);
				copyOfLungs->SetPixel(currentIndexLung,(char)(0));
			}	
		}
	}

	//Se mira la imagen binaria de los pulmones, y de acuerdo a los pixeles con un valor de 1, se revisa en la imagen inicial si cumplen con el criterio de intensidad.
	for (int i=0 ; i< sizeLung[0] ; i++)
	{
		for (int j=0; j< sizeLung[1]; j++)
		{
			for (int k=0; k<sizeLung [2]; k++)
			{
				ImageType::IndexType currentIndex;
				currentIndex[0] = i;
				currentIndex[1] = j;
				currentIndex[2] = k;
				ImageType::PixelType currentValue = imageIn->GetPixel(currentIndex);

				ImageBinaryType::IndexType currentIndexB;
				currentIndexB[0] = i;
				currentIndexB[1] = j;
				currentIndexB[2] = k;
				ImageBinaryType::PixelType currentValueB = pulmones->GetPixel(currentIndexB);
				
				if(currentValue>-150 && (int)currentValueB==255){
					copyOfLungs->SetPixel(currentIndexB,char(255));
				}
			}
		}
	}
	
  /*
	//imprimirMatriz(reader->GetOutput()); //No SIRVE 
  
 	ImageType::Pointer image = openingFilter->GetOutput();
	ImageType::SizeType size = openingFilter->GetOutput()->GetLargestPossibleRegion().GetSize();
	ImageType::IndexType index = openingFilter->GetOutput()->GetLargestPossibleRegion().GetIndex();
  
	cout<<" Size :  "<<size<<endl;
	//cout<<" 22222222222 :  "<<index<<endl;  
*/
/*
	for (int i=0 ; i< size[0] ; i++)
	{
		for (int j=0; j< size[1]; j++)
		{
			for (int k=0; k<size [2]; k++)
			{
				
				ImageType::IndexType currentIndex;
				currentIndex[0] = i;
				currentIndex[1] = j;
				currentIndex[2] = k;
				ImageType::PixelType currentValue = image->GetPixel(currentIndex);
				
				if(currentValue<=0){
					image->SetPixel(currentIndex,0);
				}
				else
				{
					image->SetPixel(currentIndex,10);
				}
				
				//cout<<currentValue<<"   ";
			}
			
		}
		//cout<<endl;
	}


*/

/*
  
	for (int i=0 ; i< size[0] ; i++)
	{
		for (int j=0; j< size[1]; j++)
		{
			for (int k=0; k<size [2]; k++)
			{
				ImageType::IndexType currentIndex;
				currentIndex[0] = i;
				currentIndex[1] = j;
				currentIndex[2] = k;
				ImageType::PixelType currentValue = image->GetPixel(currentIndex);
				cout<<currentValue<<"   ";
			}
			
		}
		cout<<endl;
	}
*/
  
  imageOut=copyOfLungs;
  //Salida 
  
  const char * outputDirectory = argv[2];
  itksys::SystemTools::MakeDirectory( outputDirectory );
  


  //  We construct a series writer and connect to its input the output from the
  //  reader. Then we pass the GDCM image IO object in order to be able to write
  //  the images in DICOM format.

  SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
  //seriesWriter->SetInput( closingFilter->GetOutput() );
  seriesWriter->SetInput( imageOut);

  seriesWriter->SetImageIO( gdcmIO );
  //  It is time now to setup the GDCMSeriesFileNames to generate new filenames
  //  using another output directory.  Then simply pass those newly generated
  //  files to the series writer.
  namesGenerator->SetOutputDirectory( outputDirectory );
  seriesWriter->SetFileNames( namesGenerator->GetOutputFileNames() );
  //  The line is taking the MetaDataDictionary from the input reader
  //  and passing it to the output writer. 
  seriesWriter->SetMetaDataDictionaryArray(reader->GetMetaDataDictionaryArray() );
  
	try
	{
		seriesWriter->Update();
    }
	catch( itk::ExceptionObject & excp )
    {
		std::cerr << "Exception thrown while writing the series " << std::endl;
		std::cerr << excp << std::endl;
		return EXIT_FAILURE;
    }

	//imageOut = imageBinary;

	//Para mostrar las imagenes procesadas
	const char * inputDirectory = argv[1];
	leerImagenes(inputDirectory,outputDirectory);
  return EXIT_SUCCESS;
}
/*
Tarballs of the nightly generated Doxygen documentation are available for the html, xml, and tag file.
Generated on Mon May 12 2014 01:40:36 for ITK by   doxygen 1.8.5
*/

void leerImagenes(string folder, string folder2){
	
	//Entrada
   vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New();
   reader->SetDirectoryName(folder.c_str());
   reader->Update();
 
   // Visualize
   vtkSmartPointer<vtkImageViewer2> imageViewer = vtkSmartPointer<vtkImageViewer2>::New();
   imageViewer->SetInputConnection(reader->GetOutputPort());
 
   // slice status message
   vtkSmartPointer<vtkTextProperty> sliceTextProp = vtkSmartPointer<vtkTextProperty>::New();
   sliceTextProp->SetFontFamilyToCourier();
   sliceTextProp->SetFontSize(20);
   sliceTextProp->SetVerticalJustificationToBottom();
   sliceTextProp->SetJustificationToLeft();
 
   vtkSmartPointer<vtkTextMapper> sliceTextMapper = vtkSmartPointer<vtkTextMapper>::New();
   std::string msg = StatusMessage::Format(imageViewer->GetSliceMin(), imageViewer->GetSliceMax());
   sliceTextMapper->SetInput(msg.c_str());
   sliceTextMapper->SetTextProperty(sliceTextProp);
 
   vtkSmartPointer<vtkActor2D> sliceTextActor = vtkSmartPointer<vtkActor2D>::New();
   sliceTextActor->SetMapper(sliceTextMapper);
   sliceTextActor->SetPosition(15, 10);
 
   // usage hint message
   vtkSmartPointer<vtkTextProperty> usageTextProp = vtkSmartPointer<vtkTextProperty>::New();
   usageTextProp->SetFontFamilyToCourier();
   usageTextProp->SetFontSize(14);
   usageTextProp->SetVerticalJustificationToTop();
   usageTextProp->SetJustificationToLeft();
 
   vtkSmartPointer<vtkTextMapper> usageTextMapper = vtkSmartPointer<vtkTextMapper>::New();
   //usageTextMapper->SetInput("- Slice with mouse wheel\n  or Up/Down-Key\n- Zoom with pressed right\n  mouse button while dragging");
    usageTextMapper->SetInput("Entrada");
   usageTextMapper->SetTextProperty(usageTextProp);
 
   vtkSmartPointer<vtkActor2D> usageTextActor = vtkSmartPointer<vtkActor2D>::New();
   usageTextActor->SetMapper(usageTextMapper);
   usageTextActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedDisplay();
   usageTextActor->GetPositionCoordinate()->SetValue( 0.05, 0.95);
 
   // create an interactor with our own style (inherit from vtkInteractorStyleImage)
   // in order to catch mousewheel and key events
   vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
 
   vtkSmartPointer<myVtkInteractorStyleImage> myInteractorStyle = vtkSmartPointer<myVtkInteractorStyleImage>::New();
 
   // make imageviewer2 and sliceTextMapper visible to our interactorstyle
   // to enable slice status message updates when scrolling through the slices
   myInteractorStyle->SetImageViewer(imageViewer);
   myInteractorStyle->SetStatusMapper(sliceTextMapper);
 
   imageViewer->SetupInteractor(renderWindowInteractor);
   // make the interactor use our own interactorstyle
   // cause SetupInteractor() is defining it's own default interatorstyle 
   // this must be called after SetupInteractor()
   renderWindowInteractor->SetInteractorStyle(myInteractorStyle);
   // add slice status message and usage hint message to the renderer
   imageViewer->GetRenderer()->AddActor2D(sliceTextActor);
   imageViewer->GetRenderer()->AddActor2D(usageTextActor);
 
   // initialize rendering and interaction
   //imageViewer->GetRenderWindow()->SetSize(400, 300);
   //imageViewer->GetRenderer()->SetBackground(0.2, 0.3, 0.4);
   imageViewer->Render();
   imageViewer->GetRenderer()->ResetCamera();
   imageViewer->Render();
   

   
   
   //Salida
   vtkSmartPointer<vtkDICOMImageReader> reader2 = vtkSmartPointer<vtkDICOMImageReader>::New();
   reader2->SetDirectoryName(folder2.c_str());
   reader2->Update();
 
   // Visualize
   vtkSmartPointer<vtkImageViewer2> imageViewer2 = vtkSmartPointer<vtkImageViewer2>::New();
   imageViewer2->SetInputConnection(reader2->GetOutputPort());
 
   // slice status message
   vtkSmartPointer<vtkTextProperty> sliceTextProp2 = vtkSmartPointer<vtkTextProperty>::New();
   sliceTextProp2->SetFontFamilyToCourier();
   sliceTextProp2->SetFontSize(20);
   sliceTextProp2->SetVerticalJustificationToBottom();
   sliceTextProp2->SetJustificationToLeft();
 
   vtkSmartPointer<vtkTextMapper> sliceTextMapper2 = vtkSmartPointer<vtkTextMapper>::New();
   std::string msg2 = StatusMessage::Format(imageViewer2->GetSliceMin(), imageViewer2->GetSliceMax());
   sliceTextMapper2->SetInput(msg2.c_str());
   sliceTextMapper2->SetTextProperty(sliceTextProp2);
 
   vtkSmartPointer<vtkActor2D> sliceTextActor2 = vtkSmartPointer<vtkActor2D>::New();
   sliceTextActor2->SetMapper(sliceTextMapper2);
   sliceTextActor2->SetPosition(15, 10);
 
   // usage hint message
   vtkSmartPointer<vtkTextProperty> usageTextProp2 = vtkSmartPointer<vtkTextProperty>::New();
   usageTextProp2->SetFontFamilyToCourier();
   usageTextProp2->SetFontSize(14);
   usageTextProp2->SetVerticalJustificationToTop();
   usageTextProp2->SetJustificationToLeft();
 
   vtkSmartPointer<vtkTextMapper> usageTextMapper2 = vtkSmartPointer<vtkTextMapper>::New();
   //usageTextMapper->SetInput("- Slice with mouse wheel\n  or Up/Down-Key\n- Zoom with pressed right\n  mouse button while dragging");
   usageTextMapper2->SetInput("Salida");
   usageTextMapper2->SetTextProperty(usageTextProp2);
 
   vtkSmartPointer<vtkActor2D> usageTextActor2 = vtkSmartPointer<vtkActor2D>::New();
   usageTextActor2->SetMapper(usageTextMapper2);
   usageTextActor2->GetPositionCoordinate()->SetCoordinateSystemToNormalizedDisplay();
   usageTextActor2->GetPositionCoordinate()->SetValue( 0.05, 0.95);
 
   // create an interactor with our own style (inherit from vtkInteractorStyleImage)
   // in order to catch mousewheel and key events
   vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor2 = vtkSmartPointer<vtkRenderWindowInteractor>::New();
 
   vtkSmartPointer<myVtkInteractorStyleImage> myInteractorStyle2 = vtkSmartPointer<myVtkInteractorStyleImage>::New();
 
   // make imageviewer2 and sliceTextMapper visible to our interactorstyle
   // to enable slice status message updates when scrolling through the slices
   myInteractorStyle2->SetImageViewer(imageViewer2);
   myInteractorStyle2->SetStatusMapper(sliceTextMapper2);
 
   imageViewer2->SetupInteractor(renderWindowInteractor2);
   // make the interactor use our own interactorstyle
   // cause SetupInteractor() is defining it's own default interatorstyle 
   // this must be called after SetupInteractor()
   renderWindowInteractor2->SetInteractorStyle(myInteractorStyle2);
   // add slice status message and usage hint message to the renderer
   imageViewer2->GetRenderer()->AddActor2D(sliceTextActor2);
   imageViewer2->GetRenderer()->AddActor2D(usageTextActor2);
 
   // initialize rendering and interaction
   //imageViewer->GetRenderWindow()->SetSize(400, 300);
   //imageViewer->GetRenderer()->SetBackground(0.2, 0.3, 0.4);
   imageViewer2->Render();
   imageViewer2->GetRenderer()->ResetCamera();
   imageViewer2->Render();
      
	  
	//Para mirar el valor del pixel// el metodo del click ya se puso en el estilo principal
/*
	vtkSmartPointer<MouseInteractorStylePP> style = vtkSmartPointer<MouseInteractorStylePP>::New();
	vtkSmartPointer<MouseInteractorStylePP> style2 = vtkSmartPointer<MouseInteractorStylePP>::New();
	  
	renderWindowInteractor->SetInteractorStyle( style );   
	renderWindowInteractor2->SetInteractorStyle( style2 );

  */
   renderWindowInteractor->Start();
   renderWindowInteractor2->Start();
}


//Leer todos los datos del diccionario de metadata
void leerEncabezado (string nombre){
	
	ReaderType::Pointer reader = ReaderType::New();
	
	typedef itk::GDCMImageIO       ImageIOType;
	ImageIOType::Pointer dicomIO = ImageIOType::New();
	
	reader->SetImageIO( dicomIO );
		
	typedef itk::GDCMSeriesFileNames     NamesGeneratorType;
	NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
	nameGenerator->SetInputDirectory(nombre);
	
	typedef std::vector<std::string>    FileNamesContainer;
	FileNamesContainer fileNames = nameGenerator->GetInputFileNames();
	
	reader->SetFileNames( fileNames );
	
	try
    {
		reader->Update();
    }
	catch (itk::ExceptionObject &ex)
    {
		std::cout << ex << std::endl;
		return ;
    }
	
	typedef itk::MetaDataDictionary   DictionaryType;
	const  DictionaryType & dictionary = dicomIO->GetMetaDataDictionary();
	typedef itk::MetaDataObject< std::string > MetaDataStringType;
	
	DictionaryType::ConstIterator itr = dictionary.Begin();
	DictionaryType::ConstIterator end = dictionary.End();
	
	
	cout<<endl<<endl<<"---VALORES DEL METADATA---"<<endl;
	while( itr != end )
    {
		itk::MetaDataObjectBase::Pointer  entry = itr->second;
		MetaDataStringType::Pointer entryvalue =
		  dynamic_cast<MetaDataStringType *>( entry.GetPointer() );
		if( entryvalue )
		  {
			  std::string tagkey   = itr->first;
			  std::string tagvalue = entryvalue->GetMetaDataObjectValue();
			  std::cout << tagkey <<  " = " << tagvalue << std::endl;
		  }
		++itr;
    }
	
	
	std::string entryId = "0028|1054";
	
	
	cout<<endl<<endl<<"Tag de "<<entryId<<endl;
	DictionaryType::ConstIterator tagItr = dictionary.Find( entryId );
	
	if( tagItr == end )
    {
		std::cerr << "Tag " << entryId;
		std::cerr << " not found in the DICOM header" << std::endl;
		return ;
    }
	
	 MetaDataStringType::ConstPointer entryvalue =
    dynamic_cast<const MetaDataStringType *>( tagItr->second.GetPointer() );

	 if( entryvalue )
    {
		std::string tagvalue = entryvalue->GetMetaDataObjectValue();
		std::cout << "Patient's Name (" << entryId <<  ") ";
		std::cout << " is: " << tagvalue << std::endl;
    }
	else
    {
		std::cerr << "Entry was not of string type" << std::endl;
		return;
    }	
	 
}
//Lee el archivo de encabezado o metadata solo para obtener el valor en mm que corresponde al pixel
double obtenerValorDePixel(string nombreDir){
	
	ReaderType::Pointer reader = ReaderType::New();
	
	typedef itk::GDCMImageIO       ImageIOType;
	ImageIOType::Pointer dicomIO = ImageIOType::New();
	
	reader->SetImageIO( dicomIO );
		
	typedef itk::GDCMSeriesFileNames     NamesGeneratorType;
	NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
	nameGenerator->SetInputDirectory(nombreDir);
	
	typedef std::vector<std::string>    FileNamesContainer;
	FileNamesContainer fileNames = nameGenerator->GetInputFileNames();
	
	reader->SetFileNames( fileNames );
	
	try
    {
		reader->Update();
    }
	catch (itk::ExceptionObject &ex)
    {
		std::cout << ex << std::endl;
		return -1;
    }
	
	typedef itk::MetaDataDictionary   DictionaryType;
	const  DictionaryType & dictionary = dicomIO->GetMetaDataDictionary();
	typedef itk::MetaDataObject< std::string > MetaDataStringType;
	
	DictionaryType::ConstIterator itr = dictionary.Begin();
	DictionaryType::ConstIterator end = dictionary.End();
	

	std::string entryId = "0028|0030";
	DictionaryType::ConstIterator tagItr = dictionary.Find( entryId );
	
	if( tagItr == end )
    {
		std::cerr << "Tag " << entryId;
		std::cerr << " not found in the DICOM header" << std::endl;
		return -1;
    }
	
	 MetaDataStringType::ConstPointer entryvalue =
    dynamic_cast<const MetaDataStringType *>( tagItr->second.GetPointer() );

	 if( entryvalue )
    {
		std::string tagvalue = entryvalue->GetMetaDataObjectValue();
		return atof(tagvalue.c_str());
    }
	else
    {
		std::cerr << "Entry was not of string type" << std::endl;
		return -1;
    }
}




double obtenerValorDePixel(itk::GDCMImageIO::Pointer dicomIO){
	
	typedef itk::MetaDataDictionary   DictionaryType;
	const  DictionaryType & dictionary = dicomIO->GetMetaDataDictionary();
	typedef itk::MetaDataObject< std::string > MetaDataStringType;
	
	DictionaryType::ConstIterator itr = dictionary.Begin();
	DictionaryType::ConstIterator end = dictionary.End();
	

	std::string entryId = "0028|0030";
	DictionaryType::ConstIterator tagItr = dictionary.Find( entryId );
	
	if( tagItr == end )
    {
		std::cerr << "Tag " << entryId;
		std::cerr << " not found in the DICOM header" << std::endl;
		return -1;
    }
	
	 MetaDataStringType::ConstPointer entryvalue =
    dynamic_cast<const MetaDataStringType *>( tagItr->second.GetPointer() );

	 if( entryvalue )
    {
		std::string tagvalue = entryvalue->GetMetaDataObjectValue();
		return atof(tagvalue.c_str());
    }
	else
    {
		std::cerr << "Entry was not of string type" << std::endl;
		return -1;
    }
}


